﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Configuration;
using SdmxMl.Common;
using SdmxMl.Structure;
using SdmxMl.GenericMetadata;
using SdmxMl.Helper;
using SdmxMl.Msg;
using SdmxMl.Panels;
using SdmxMl.UC;
using SdmxMl.Excel;
using SdmxMl.Data;
using SdmxMl.Multiplexor;

namespace SdmxMl.Manager
{
    /// <summary> Publishes the method definition in the form of a delegate </summary>
    /// <param name="sender"></param>/ <param name="e">CancelEventArgs instance</param>
    public delegate void UserQuitEvent(object sender, CancelEventArgs e);

    /// <summary>
    /// Manage operations on Treeview where SDMX artefacts are attached
    /// </summary>
    public class TreeSdmxManager
    {
        private const string ITEM_REF_SDMX = "SDMX Ref.";
        private const string ITEM_REF_REST = "REST Ref.";
        private const string ITEM_REF_CSV = "CSV Export Ref.";
        private const string ITEM_REF_FILE = "File Ref.";



        #region Internal Members

        private SdmxNamespaceManager nsmgr = null;
        private MoveableTreeView tv;
        private SaveFileDialog saveFileDlg;
        private TreeSdmxPopupMenuManager treePopupManager;
        private ToolStripMenuItem tsMenuCsv;
        private ToolStripMenuItem semicolumnToolStripMenuItem;
        private ToolStripMenuItem tabulationToolStripMenuItem;
        private ToolStripMenuItem findInAnnotationsToolStripMenuItem;
        private ToolStripButton toolStripButtonSortList;
        private DlgMemoryRef _dlgMemoryRef;
        private DlgReferrer _dlgReferrer;
        private DlgDataCsv _dlgDataCsv;
        private CsvProperties CsvConfig;
        private DlgDsdWizard _dlgDsdWizard;
        private DlgSearchAnnotations _dlgSearchAnnot;

        #endregion // Internal Members

        #region Construction

        public TreeSdmxManager()
        {
            saveFileDlg = new SaveFileDialog();
            saveFileDlg.Filter = "Sdmx Files|*.xml|All Files|*.*";

            //To update state at start
            if (string.IsNullOrEmpty(Mux.Instance.ErrorStateMessage) == false)
                throw new ApplicationException(Mux.Instance.ErrorStateMessage);

            // CSV Data reader config
            CsvConfig = new CsvProperties();
        }
        #endregion // Construction

        #region Properties

        // Selected item can be saved as SDMX file ?
        public bool IsItemWritable
        {
            get
            {
                return treePopupManager.IsItemWritable;
            }
        }

        /// <summary>
        /// The treeview control where to attach SDMX artefacts
        /// </summary>
        public MoveableTreeView TV
        {
            get { return tv; }
            set
            {
                if (tv != null)
                {
                    treePopupManager = null;
                    tv.AfterSelect -= new TreeViewEventHandler(this.treeView_AfterSelect);
                    tv.BeforeSelect -= new System.Windows.Forms.TreeViewCancelEventHandler(this.treeView_BeforeSelect);
                    tv.NodeMouseClick -= new System.Windows.Forms.TreeNodeMouseClickEventHandler(this.treeView_NodeMouseClick);
                    tv.BeforeNodeMove -= new MoveableTreeView.BeforeNodeMoveHandler(tv_BeforeNodeMove);
                    tv.AfterNodeMove -= new MoveableTreeView.AfterNodeMoveHandler(tv_AfterNodeMove);
                }
               
                // New one
                tv = value;
                treePopupManager = new TreeSdmxPopupMenuManager(tv);
                treePopupManager.SaveArtefactEventExposed += new SaveArtefactEvent(treePopupManager_SaveArtefactEventExposed);
                treePopupManager.CopyArtefactRefEventExposed += new CopyArtefactRefEvent(copyArtefactRefToolStripMenuItem_Click);
                tv.AfterSelect += new TreeViewEventHandler(this.treeView_AfterSelect);
                tv.BeforeSelect += new System.Windows.Forms.TreeViewCancelEventHandler(this.treeView_BeforeSelect);
                tv.NodeMouseClick += new System.Windows.Forms.TreeNodeMouseClickEventHandler(this.treeView_NodeMouseClick);
                tv.BeforeNodeMove += new MoveableTreeView.BeforeNodeMoveHandler(tv_BeforeNodeMove);
                tv.AfterNodeMove += new MoveableTreeView.AfterNodeMoveHandler(tv_AfterNodeMove);
                PrepareManagers();
            }
        }

        /// <summary>
        /// Invokes Uri, if syntax is SDMX artefact ref, try to load from registry
        /// </summary>
        /// <param name="uri"></param> <param name="art"></param>
        public void ActivateUri(string uri, ArtefactRefTyped art)
        {
            try
            {
                if (uri != null)
                {
                    if (art != null)
                    {
                        UrnParser p = new UrnParser(uri);

                        // If already in memory, navigate otherwhile get from regidtry
                        if (NavigationManager.LocatenavigateProject(art.Type, art.FullIdent, p) == null)
                            NavigationManager.NavigateWithRegistry(art.Type, art.FullIdent, true, p);
                    }
                    else
                    {
                        // Try to process document
                        System.Diagnostics.Process myProc;
                        myProc = System.Diagnostics.Process.Start(uri);
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }


        /// <summary>
        /// Manager for menu & buttons events dedicated to repository
        /// </summary>
        public RepositoryMenuManager RepositoryMenuMgr { get; set; }


        /// <summary> Event for save artefact request</summary>
        /// <param name="sender"></param><param name="a"></param>
        void treePopupManager_SaveArtefactEventExposed(object sender, EventArgs a)
        {
            SaveArtefact(tv.SelectedNode);
        }

        // Status bar (info text)
        private StatusStrip _statusStrip;
        private ToolStripStatusLabel _toolstripLabelInfo;
        private ToolStripStatusLabel _toolstripLabelInfoRepository;


        public StatusStrip StatusStripBar
        {
            get { return _statusStrip; }
            set
            {
                // The toolstrip info will be used for info text if available
                _toolstripLabelInfo = null;
                _statusStrip = value;
                foreach (ToolStripItem tsi in _statusStrip.Items)
                    if (tsi is ToolStripStatusLabel)
                    {
                        if (_toolstripLabelInfo == null)
                            _toolstripLabelInfo = tsi as ToolStripStatusLabel;
                        else if (_toolstripLabelInfoRepository == null)
                            _toolstripLabelInfoRepository = tsi as ToolStripStatusLabel;
                    }
            }
        }

        //
        private ToolStripMenuItem copyArtefactRefToolStripMenuItem;
        public ToolStripMenuItem CopyArtefactRefToolStripMenuItem
        {
            get { return copyArtefactRefToolStripMenuItem; }

            set
            {
                copyArtefactRefToolStripMenuItem = value;
                if (copyArtefactRefToolStripMenuItem != null)
                {
                    // Add 4 sub Menus
                    string[] sub = new string[] { ITEM_REF_SDMX, ITEM_REF_REST, ITEM_REF_CSV, ITEM_REF_FILE };
                    int i = 0;
                    foreach (string s in sub)
                    {
                        ToolStripMenuItem m = new ToolStripMenuItem();

                        m.Text = s;
                        m.Tag = i++;

                        // attach to parent
                        copyArtefactRefToolStripMenuItem.DropDownItems.Add(m);

                        // create click event
                        m.Click += new EventHandler(this.copyArtefactRefToolStripMenuItem_Click);
                    }


                    copyArtefactRefToolStripMenuItem.Enabled = false;
                    //copyArtefactRefToolStripMenuItem.Click += 
                    //    new System.EventHandler(this.copyArtefactRefToolStripMenuItem_Click);
                }
            }

        }

        public ToolStripMenuItem FindInAnnotationsToolStripMenuItem
        {
            get { return findInAnnotationsToolStripMenuItem; }

            set
            {
                findInAnnotationsToolStripMenuItem = value;
                if (findInAnnotationsToolStripMenuItem != null)
                {
                    findInAnnotationsToolStripMenuItem.Click +=
                        new EventHandler(this.FindInAnnotationsToolStripMenuItem_Click);
                }
            }

        }


        private ToolStripMenuItem _dSDWizardToolStripMenuItem;
        public ToolStripMenuItem DSDWizardToolStripMenuItem
        {
            get { return _dSDWizardToolStripMenuItem; }

            set
            {
                _dSDWizardToolStripMenuItem = value;
                if (_dSDWizardToolStripMenuItem != null)
                {
                    _dSDWizardToolStripMenuItem.Enabled = true;
                    _dSDWizardToolStripMenuItem.Click += new EventHandler(DSDWizardToolStripMenuItem_Click);
                }
            }
        }


        private ToolStripMenuItem _csvDataToolStripMenuItem;
        public ToolStripMenuItem CsvDataToolStripMenuItem
        {
            get { return _csvDataToolStripMenuItem; }

            set
            {
                _csvDataToolStripMenuItem = value;
                if (_csvDataToolStripMenuItem != null)
                {
                    _csvDataToolStripMenuItem.Enabled = true;
                    _csvDataToolStripMenuItem.Click += new System.EventHandler(this.cSVToolStripMenuItem_Click);
                }
            }
        }



        private ToolStripMenuItem excelToolStripMenuItem;
        public ToolStripMenuItem ExportExcelToolStripMenuItem
        {
            get { return excelToolStripMenuItem; }

            set
            {
                excelToolStripMenuItem = value;
                if (excelToolStripMenuItem != null)
                {
                    excelToolStripMenuItem.Enabled = false;
                    excelToolStripMenuItem.Click += new System.EventHandler(this.ExcelToolStripMenuItem_Click);
                }
            }
        }


        private ToolStripMenuItem saveSelectedArtefactToolStripMenuItem;
        private ToolStripButton toolStripButtonSaveArtefact;
        public ToolStripMenuItem SaveSelectedArtefactToolStripMenuItem
        {
            get { return saveSelectedArtefactToolStripMenuItem; }

            set
            {
                saveSelectedArtefactToolStripMenuItem = value;
                if (treePopupManager != null)
                    treePopupManager.SaveSelectedArtefactToolStripMenuItem = saveSelectedArtefactToolStripMenuItem;
                if (saveSelectedArtefactToolStripMenuItem != null)
                {
                    saveSelectedArtefactToolStripMenuItem.Enabled = false;
                    saveSelectedArtefactToolStripMenuItem.Click += new System.EventHandler(this.treePopupManager_SaveArtefactEventExposed);
                }
            }
        }

        public ToolStripButton ToolStripButtonSaveArtefact
        {
            get { return toolStripButtonSaveArtefact; }

            set
            {
                toolStripButtonSaveArtefact = value;
                if (treePopupManager != null)
                    treePopupManager.ToolStripButtonSaveArtefact = toolStripButtonSaveArtefact;
                if (toolStripButtonSaveArtefact != null)
                {
                    toolStripButtonSaveArtefact.Enabled = false;
                    toolStripButtonSaveArtefact.Click += new System.EventHandler(treePopupManager_SaveArtefactEventExposed);
                }
            }
        }

        private ucPanelDetail panelDetail;
        public ucPanelDetail PanelDetail
        {
            get { return panelDetail; }
            set
            {
                panelDetail = value;
                if (treePopupManager != null)
                    treePopupManager.PanelDetail = panelDetail;

            }
        }
        
        #endregion //Properties

        #region CSV Export

        public void AttachCsvToolStrips(ToolStripMenuItem csvRoot, ToolStripMenuItem csvComma,
            ToolStripMenuItem csvSemi, ToolStripMenuItem csvTab)
        {
            tsMenuCsv = csvRoot;
            tsMenuCsv.Enabled = false;
            semicolumnToolStripMenuItem = csvSemi;
            tabulationToolStripMenuItem = csvTab;
            csvComma.Click += new EventHandler(CSV_ExportToolStripMenuItem_Click);
            csvSemi.Click += new EventHandler(CSV_ExportToolStripMenuItem_Click);
            csvTab.Click += new EventHandler(CSV_ExportToolStripMenuItem_Click);

        }

        private void CSV_ExportToolStripMenuItem_Click(object sender, EventArgs e)
        {
            char separator = ',';

            if (sender == semicolumnToolStripMenuItem)
                separator = ';';
            else if (sender == tabulationToolStripMenuItem)
                separator = '\t';

            try
            {
                if (tv.SelectedNode != null)
                {
                    Artefact a = tv.SelectedNode.Tag as Artefact;
                    CodeListType clt = tv.SelectedNode.Tag as CodeListType;
                    HierarchicalCodelistType hcl = tv.SelectedNode.Tag as HierarchicalCodelistType;
                    SdmxMl.Excel.CsvExportNomen csv = null;

                    if (clt != null)
                        csv = new SdmxMl.Excel.CsvExportNomen(clt, separator);
                    if (hcl != null)
                        csv = new SdmxMl.Excel.CsvExportNomen(hcl, separator);
                    if (csv != null)
                    {
                        SaveFileDialog sfd = new SaveFileDialog();
                        sfd.DefaultExt = ".csv";
                        sfd.FileName = "C:\\" + a.FullIdent + ".csv";
                        if (sfd.ShowDialog() == DialogResult.OK)
                            csv.Export(sfd.FileName);
                    }
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

        }

        #endregion

        #region EventsHandler

        public event EventHandler TreeBeforeSelect;

        public void RaiseTreeBeforeSelect(TreeViewCancelEventArgs e)
        {
            EventHandler eventHandler = this.TreeBeforeSelect;
            if (eventHandler != null)
                this.TreeBeforeSelect(this, e);
        }
        public event EventHandler AppliClosing;
        public void RaiseAppliClosing()
        {
            EventHandler eventHandler = this.AppliClosing;
            if (eventHandler != null)
                this.AppliClosing(this, EventArgs.Empty);
        }

        public event EventHandler TreeSelect;
        public void RaiseTreeSelect()
        {
            EventHandler eventHandler = this.TreeSelect;
            if (eventHandler != null)
                this.TreeSelect(this, EventArgs.Empty);
        }

        public event EventHandler LanguageChange;
        public void RaiseLanguageChange()
        {
            EventHandler eventHandler = this.LanguageChange;

            if (eventHandler != null)
                this.LanguageChange(this, EventArgs.Empty);
        }



        public event UserQuitEvent UserQuitEventExposed;
        public bool RaiseUserQuit()
        {
            CancelEventArgs evArg = new CancelEventArgs();
            UserQuitEvent eventHandler = this.UserQuitEventExposed;
            if (eventHandler != null)
                eventHandler(this, evArg);
            return evArg.Cancel;
        }


        #endregion //EventsHandler

        #region Language

        public void RefreshDetailView()
        {
            if (tv != null && tv.SelectedNode != null)
                treeView_AfterSelect(this, new TreeViewEventArgs(tv.SelectedNode));
        }

        /// <summary>Display language change request</summary>
        /// <param name="langIndex">index in supported languages list</param>
        public void ChangeCurrentLanguage(int langIndex)
        {
            new CWaitCursor();
            // Update from current detail view
            if (panelDetail != null)
                panelDetail.UpdateNodeTag(tv.SelectedNode);

            // Change current language
            LangSupport.CurLangIndex = langIndex;
            RefreshDetailView();

            // Translate nodes
            TreeViewDrawMode tvMode = tv.DrawMode;
            tv.DrawMode = TreeViewDrawMode.Normal;
            tv.BeginUpdate();
            foreach (TreeNode node in tv.Nodes)
                TreeViewUpdateLang(node);
            tv.EndUpdate();
            tv.DrawMode = tvMode;

            RaiseLanguageChange();
        }

        /// <summary>
        /// Refresh tree nodes text according to current language
        /// </summary>
        /// <param name="node"></param>
        private void TreeViewUpdateLang(TreeNode node)
        {
            if (node.Tag != null)
                node.Text = node.Tag.ToString();

            foreach (TreeNode n in node.Nodes)
                TreeViewUpdateLang(n);
        }

        #endregion Language

        #region Expand Collapse Nodes

        /// <summary>Toggle tree node opening</summary>
        public void ToggleFromSelectedLevel()
        {
            if (tv.SelectedNode != null)
            {

                tv.DrawMode = TreeViewDrawMode.Normal;
                tv.BeginUpdate();

                // if no child operate on parent if possible
                TreeNode n = tv.SelectedNode;
                if (n.Nodes.Count == 0 && n.Parent != null)
                {
                    panelDetail.UpdateNodeTag(n);
                    panelDetail.BindFromNode(null);
                    n = n.Parent;
                    tv.SelectedNode = n;
                }

                if (n.IsExpanded)
                    n.Collapse();
                else
                    n.ExpandAll();
                n.EnsureVisible();
                tv.EndUpdate();
                tv.DrawMode = System.Windows.Forms.TreeViewDrawMode.OwnerDrawText;

            }
        }

        #endregion //Expand Collapse Nodes

        #region Move Node

        void tv_AfterNodeMove(object sender, MoveableTreeView.AfterNodeMoveEventArgs e)
        {
            if (e != null && e.MovedNode != null)
            {
                Artefact artefact = e.MovedNode.Tag as Artefact;

                // Reorder Artefact in artefact list
                if (artefact != null)
                {
                    ArtefactManager am = e.MovedNode.Parent.Tag as ArtefactManager;
                    if (am != null)
                    {
                        am.ArtefactList.Remove(artefact);
                        am.ArtefactList.Insert(e.NewIndex, artefact);
                    }
                }

                // Reorder items of an artefact collection of items
                else
                {
                    ISdmxHierarchyListItem item = e.MovedNode.Tag as ISdmxHierarchyListItem;
                    if (item != null)
                    {
                        TreeNode nodeHierarchy = TreeHelper.GetHierarchyManage(e.MovedNode);
                        if (nodeHierarchy != null)
                        {
                            IHierarchyManage ihm = nodeHierarchy.Tag as IHierarchyManage;
                            if (ihm != null)
                            {
                                // All items on same level (even if hierarchy is exprimed)
                                if (ihm is FlatHierarchicalList)
                                {
                                    FlatHierarchicalList fhl = ihm as FlatHierarchicalList;
                                    if (e.NewIndex > 0)
                                    {
                                        ISdmxHierarchyListItem prevItem = e.MovedNode.Parent.Nodes[e.NewIndex - 1].Tag as ISdmxHierarchyListItem;
                                        fhl.Remove(item);
                                        int ndx = fhl.IndexOf(prevItem);
                                        fhl.Insert(ndx + 1, item);

                                    }
                                    else
                                    {
                                        // Previous can be a parent item. If none, we assume start position for moved one
                                        ISdmxHierarchyListItem prevItem = e.MovedNode.Parent.Tag as ISdmxHierarchyListItem;

                                        fhl.Remove(item);
                                        int ndx = -1;
                                        if (prevItem != null)
                                            ndx = fhl.IndexOf(prevItem);
                                        fhl.Insert(ndx + 1, item);
                                    }
                                }
                                // Real hierarchical collection
                                else if (ihm is CategoryList)
                                {
                                    // The parent meta attribute collection is to be rearanged
                                    Category catParent = e.MovedNode.Parent.Tag as Category;
                                    CategoryList list = null;
                                    if (catParent == null)
                                        list = ihm as CategoryList;
                                    else
                                        list = catParent.CategoryList;

                                    Category catMoved = e.MovedNode.Tag as Category;
                                    list.Remove(catMoved);
                                    list.Insert(e.NewIndex, catMoved);
                                }
                                // Real hierarchical collection
                                else if (ihm is ProcessStepTypeList)
                                {
                                    // The parent meta attribute collection is to be rearanged
                                    ProcessStepType stepParent = e.MovedNode.Parent.Tag as ProcessStepType;
                                    ProcessStepTypeList list = null;
                                    if (stepParent == null)
                                        list = ihm as ProcessStepTypeList;
                                    else
                                        list = stepParent.ProcessStepList;

                                    ProcessStepType stepMoved = e.MovedNode.Tag as ProcessStepType;
                                    list.Remove(stepMoved);
                                    list.Insert(e.NewIndex, stepMoved);
                                }
                            }
                        }
                    }
                    else
                    {
                        AttributeValueSetType atv = e.MovedNode.Tag as AttributeValueSetType;
                        if (atv != null)
                        {
                            MetadataSetType metadata = e.MovedNode.Parent.Tag as MetadataSetType;
                            if (metadata != null)
                            {
                                metadata.AttributeValueSetList.Remove(atv);
                                metadata.AttributeValueSetList.Insert(e.NewIndex, atv);
                            }
                        }
                    }
                }
            }
        }

        void tv_BeforeNodeMove(object sender, MoveableTreeView.BeforeNodeMoveEventArgs e)
        {
            e.Cancel = true;
            TreeNode node = tv.SelectedNode;
            if (node != null)
            {

                object tag = node.Tag;

                // Update readonly information
                bool readOnly = true;
                Artefact artefact = tag as Artefact;
                if (artefact == null)
                    artefact = TreeHelper.GetParentArtefact(node);
                if (artefact != null)
                    readOnly = artefact.IsFinal;

                if (readOnly == false)
                {
                    if (tag is Artefact)
                        e.Cancel = false;
                    else if (tag is ISdmxHierarchyListItem)
                        e.Cancel = false;
                    else if (tag is AttributeValueSetType)
                        e.Cancel = false;
                }
            }
        }


        #endregion //Move node

        #region Load Artefact(s)

        public void ClearAll(bool ask)
        {
            bool doIt = ask == false ||
                (MessageBox.Show("Remove all content from memory?", "Confirmation",
                             MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes);
            if (doIt)
            {
            PrepareManagers();
            NavigationManager.Reset();
            if (panelDetail != null)
                panelDetail.BindFromNode(tv.Nodes[0]);
            tv.SelectedNode = tv.Nodes[0];
            }

        }

        /// <summary>Load Artefact(s) from SDMX file Document</summary>
        /// <param name="file">file path</param>
        public void LoadSdmxArtefact(string file, bool append, XmlDocument xDoc)
        {
            new CWaitCursor();

            if (panelDetail != null)
                panelDetail.BindFromNode(null);

            // Clear actual artefacts before loading
            if (append == false)
                ClearAll(false);

            TreeNode nodeToSelect = null;
            // Read document if needed 
            if (xDoc == null && file != null && System.IO.Path.GetExtension(file).ToLower() == ".xml")
            {
                xDoc = new XmlDocument();
                xDoc.Load(file);
            }
            if (xDoc != null)
            {

                //Create an XmlNamespaceManager for resolving namespaces.
                nsmgr = Xmlhelper.CreateSdmxNamespace(xDoc);

                TreeNode nodeCreated = null;
                foreach (TreeNode node in tv.Nodes)
                {
                    ArtefactManager mgr = node.Tag as ArtefactManager;
                    if (mgr != null)
                    {
                        int previousCount = mgr.Count;
                        mgr.LoadFromDocument(xDoc, nsmgr);
                        nodeCreated = mgr.FillNode(node, previousCount);
                        if (nodeCreated != null)
                        {
                            nodeToSelect = nodeCreated;
                            nodeCreated.Expand();
                        }
                    }
                }

                tv.SelectedNode = nodeToSelect;
            }
        }

        /// <summary>Root nodes are all supported artefact managers</summary>
        private void PrepareManagers()
        {
            tv.BeginUpdate();
            tv.Nodes.Clear();
            TreeNode ndMgr = null;
            ArtefactManager a = null;
            foreach (SdmxArtefactType t in Enum.GetValues(typeof(SdmxArtefactType)))
            {
                int iconIndex = 1;
                if (t != SdmxArtefactType.None)
                {
                    if (t == SdmxArtefactType.DataSet)
                    {
                        a = new DataSetManager(t);
                        iconIndex = 3;
                    }
                    else if (t == SdmxArtefactType.MetadataSet)
                    {
                        a = new MetadataSetManager(t);
                        iconIndex = 2;
                    }
                    else
                        a = new ArtefactManager(t);

                    ndMgr = new TreeNode(a.ToString(), iconIndex, iconIndex);
                    ndMgr.Tag = a;
                    tv.Nodes.Add(ndMgr);
                }
            }

            tv.EndUpdate();
            ReferenceManager.TreeSdmx = tv;
        }

        #endregion //Load Artefact(s)

        #region Save Artefact(s)

        /// <summary>
        /// Save as SDMX-ML document the artefact attached to specified treview node
        /// </summary>
        /// <param name="node">Node holding the artefact</param>
        public void SaveArtefact(TreeNode node)
        {
            ISdmxArtefactRef iaRef = null;
            Artefact a = null;
            ArtefactManager am = null;
            string fullId = string.Empty;

            new CWaitCursor();

            // save current detail edited
            if (tv != null && tv.SelectedNode != null && panelDetail != null)
            {
                panelDetail.UpdateNodeTag(tv.SelectedNode);
                Artefact ai = tv.SelectedNode.Tag as Artefact;
                if (ai != null)
                    fullId = ai.FullIdent;
            }

            if (node != null)
            {
                am = node.Tag as ArtefactManager;
                if (am == null)
                {
                    a = node.Tag as Artefact;
                    if (a != null && node.Parent != null)
                    {
                        fullId = a.FullIdent;
                        am = node.Parent.Tag as ArtefactManager;
                    }
                }
                iaRef = a;
            }

                // Can operate ?
            if (am != null || node == null)
            {
                XmlTextWriter xw = null;
                try
                {
                    if (fullId.Length > 0)
                        saveFileDlg.FileName = fullId + ".xml";

                    saveFileDlg.Filter = "SDMX Files|*.xml|All Files|*.*";

                    if (saveFileDlg.ShowDialog() == DialogResult.OK && string.IsNullOrEmpty(saveFileDlg.FileName) == false)
                    {

                        xw = new XmlTextWriter(saveFileDlg.FileName, Encoding.UTF8);
                        xw.Formatting = Formatting.Indented;
                        xw.WriteStartDocument();

                        // Save whole project ?
                        if (node == null)
                        {
                            bool somethingSaved = false;
                            HeaderGenerator.GetHeader(fullId).WriteXml(xw, HeaderType.ReferenceScheme.Structure);

                            foreach (TreeNode nd in tv.Nodes)
                            {
                                am = nd.Tag as ArtefactManager;
                                if (am != null && (am is MetadataSetManager == false) && (am is DataSetManager == false))
                                {
                                    if (am.Count > 0)
                                        somethingSaved = true;
                                    am.WriteXml(xw, null);
                                }
                            }

                            if (somethingSaved == false)
                            {
                                string err = "Nothing to save!" + Environment.NewLine + Environment.NewLine +
                                    "Note: Metadataset and dataset can only be saved as selected artefact.";
                                MessageBox.Show(err, "Sdmx Write", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                            }
                        }
                        else
                        {
                            if (am is MetadataSetManager)
                            {
                                HeaderGenerator.GetHeader().WriteXml(xw, HeaderType.ReferenceScheme.MetadataSet);
                            }
                            else if (am is DataSetManager)
                                HeaderGenerator.GetHeader().WriteXml(xw, HeaderType.ReferenceScheme.DataSet);
                            else
                                HeaderGenerator.GetHeader(fullId).WriteXml(xw, HeaderType.ReferenceScheme.Structure);
                            am.WriteXml(xw, iaRef);
                        }

                        // SDMX 2.1 footer

                        xw.WriteEndDocument();
                        xw.Close();
                    }

                    // Metadataset check key uniqueness
                    if (iaRef is MetadataSetType)
                    {
                        List<string> dupliList = (iaRef as MetadataSetType).CheckKeyUnique();
                        if (dupliList.Count > 0)
                        {
                            string targets = "Caution: Duplicate keys in Metaset" + Environment.NewLine;
                            for (int i = 0; i < 5 && i < dupliList.Count; ++i )
                                targets += dupliList[i] + Environment.NewLine;
                            if (dupliList.Count > 5)
                                targets += "and more...";

                            MessageBox.Show(targets, "Check", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                        }
                    }
                }
                catch (Exception ex)
                {
                    if (xw != null)
                        xw.Close();
                    MessageBox.Show(ex.Message, "Sdmx Write", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }
        #endregion //Save Artefact(s)

        #region Treeview Selection Events

        private void treeView_BeforeSelect(object sender, TreeViewCancelEventArgs e)
        {
            if (e != null && panelDetail != null)
                if (panelDetail.UpdateNodeTag(tv.SelectedNode))
                    e.Cancel = true;
            RaiseTreeBeforeSelect(e);
        }

        private void treeView_AfterSelect(object sender, TreeViewEventArgs e)
        {
            if (tsMenuCsv != null)
                tsMenuCsv.Enabled = (e != null && e.Node != null && 
                (e.Node.Tag is HierarchicalCodelistType || e.Node.Tag is CodeListType));

            bool repositoryActiv = Mux.Instance.RunningOK;

            bool isArefactNode = e != null && e.Node != null && 
                (e.Node.Tag is Artefact || e.Node.Tag is MetadataSetType);

            ISdmxHierarchyListItem item = null;
            if (e.Node != null)
                item = e.Node.Tag as ISdmxHierarchyListItem;

            // Button activ if on a container of ISdmxHierarchyItems
            toolStripButtonSortList.Enabled = e != null && e.Node != null && 
                (e.Node.Tag is FlatHierarchicalList || (e.Node.Nodes.Count > 0 && e.Node.Nodes[0].Tag is FlatHierarchicalList));
            
            if (e != null && panelDetail != null)
                panelDetail.BindFromNode(e.Node);

            if (treePopupManager != null)
                treePopupManager.UpdateContextMenu(tv.SelectedNode);

            // Display node count if any or display registry info
            string msg = TreeHelper.CalculateNodeChilds(tv.SelectedNode);
            DisplayInfo(msg);

            if (RepositoryMenuMgr != null)
                RepositoryMenuMgr.UpdateMenuItemsState();

            if (ExportExcelToolStripMenuItem != null)
                ExportExcelToolStripMenuItem.Enabled = isArefactNode;


            if (copyArtefactRefToolStripMenuItem != null)
                copyArtefactRefToolStripMenuItem.Enabled = isArefactNode || item != null; ;
            
            RaiseTreeSelect();
        }

        /// <summary>Ensure update of selection when right click (for Popup Menu) </summary>
        /// <param name="sender"></param><param name="e"></param>
        private void treeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                tv.SelectedNode = e.Node;
                // Ensure event if selectedNode not changed already selected
                if (panelDetail != null)
                    panelDetail.UpdateNodeTag(tv.SelectedNode);
            }
        }

        #endregion //Treeview Selection Events

        #region Export Menu

        private void ExcelToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                if (tv.SelectedNode != null)
                {
                    ExcelExportBase export = null;
                    Artefact a = tv.SelectedNode.Tag as Artefact;

                    CodeListType clt = a as CodeListType;
                    if (clt != null)
                        export = new ExcelExportCodeList(clt);

                    ConceptSchemeType cst = a as ConceptSchemeType;
                    if (cst != null)
                        export = new ExcelExportConceptScheme(cst);

                    CategorySchemeType cat = a as CategorySchemeType;
                    if (cat != null)
                        export = new ExcelExportCategoryScheme(cat);

                    HierarchicalCodelistType hcl = a as HierarchicalCodelistType;
                    if (hcl != null)
                        export = new ExcelExportHCL(hcl, new SmManager());

                    MetadataStructureDefinitionType msd = a as MetadataStructureDefinitionType;
                    if (msd != null)
                        export = new ExcelExportMSD(msd, new SmManager());

                    KeyFamilyType dsd = a as KeyFamilyType;
                    if (dsd != null)
                        export = new ExcelExportDSD(dsd, ReferenceManager.GetSmContainerImage());

                    MetadataSetType metaSet = a as MetadataSetType;
                    if (metaSet != null)
                    {
                        // Check that associated MSD is in memory

                        MetadataStructureDefinitionType msdRefered = ReferenceManager.LocateArtefact(
                            SdmxArtefactType.MetadataStructureDefinitions, metaSet.MetadataStructureRef) as MetadataStructureDefinitionType;
                        if (msdRefered == null)
                            throw new ApplicationException("MSD: " + metaSet.MetadataStructureRef.FullIdent + " associated to metadataset must be loaded for Excel export");

                        export = new ExcelExportGenericMetaset(metaSet, msdRefered, ReferenceManager.GetSmContainerImage());
                    }

                    if (export != null && a != null)
                    {
                        export.Export();
                        SaveFileDialog sfd = new SaveFileDialog();
                        sfd.DefaultExt = ".xls";
                        sfd.FileName = a.FullIdent + ".xls";
                        if (sfd.ShowDialog() == DialogResult.OK)
                            export.Save(sfd.FileName);
                    }
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }


        #endregion

        #region Import / Export

        public void ImportExcel()
        {
            DlgImportExcel aDlg = new DlgImportExcel(this);
            aDlg.Show();
        }


       #endregion // Import

        #region Information Bar

        // Info in status bar
        public void DisplayInfo(string msg)
        {
            if (msg != null && _toolstripLabelInfo != null)
                _toolstripLabelInfo.Text = msg;

            // Info registry
            if (_toolstripLabelInfoRepository != null)
            {
                _toolstripLabelInfoRepository.Text = Mux.Instance.ConnectedInfo;
            }           
        }


        #endregion //Information

        #region Artefact Ref

        // Record artefact reference
        private void copyArtefactRefToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem mItem = sender as ToolStripMenuItem;
            if (tv != null && tv.SelectedNode != null)
            {
                // General case is the reference to an Artefact
                Artefact a = tv.SelectedNode.Tag as Artefact;

                ArtefactManager am = tv.SelectedNode.Parent.Tag as ArtefactManager;
                if (a != null && am != null)
                {
                    ReferenceManager.ArTypedCopyInstance = new ArtefactRefTyped(am.ArtefactType, a.Id, a.AgencyId, a.Version);
                    ReferenceManager.ArTypedCopyInstanceUrn =
                        UrnManager.FullIdToUrn(am.ArtefactType.ToString(), a.FullIdent);
                    FillClipboard(mItem, ReferenceManager.ArTypedCopyInstanceUrn);
                }
                else
                {
                    // Reference to an item contained in some artefact like concept, code.
                    ISdmxHierarchyListItem item = tv.SelectedNode.Tag as ISdmxHierarchyListItem;
                    a = TreeHelper.GetParentArtefact(tv.SelectedNode);

                    if (item != null && a != null)
                    {
                        // TreeNode ndm = TreeHelper.GetHierarchyManage(tv.SelectedNode);
                        am = TreeHelper.GetParentArtefactManager(tv.SelectedNode);
                        if (am != null)
                        {
                            ReferenceManager.ArTypedCopyInstance = new ArtefactRefTyped(am.ArtefactType, a.Id, a.AgencyId, a.Version);
                            ReferenceManager.ArTypedCopyInstanceUrn =
                                UrnManager.FullIdToUrn(am.ArtefactType.ToString(), a.FullIdent, item, null);
                            FillClipboard(mItem, ReferenceManager.ArTypedCopyInstanceUrn);
                        }
                    }

                    // Reference to a hierarchy defined in a hierarchicalcdelist
                    HierarchyType ht = tv.SelectedNode.Tag as HierarchyType;
                    if (ht != null && a != null)
                    {
                        ReferenceManager.ArTypedCopyInstance = new ArtefactRefTyped(SdmxArtefactType.HierarchicalCodelists, a.Id, a.AgencyId, a.Version);
                        ReferenceManager.ArTypedCopyInstanceUrn =
                            UrnManager.FullIdToUrn(SdmxArtefactType.HierarchicalCodelists.ToString(), a.FullIdent, ht, null);
                        FillClipboard(mItem, ReferenceManager.ArTypedCopyInstanceUrn);
                    }

                    // Metadataset reference to a row of the set.
                    AttributeValueSetType atv = tv.SelectedNode.Tag as AttributeValueSetType;
                    if (atv != null && a != null)
                    {
                        ReferenceManager.ArTypedCopyInstance = new ArtefactRefTyped(SdmxArtefactType.MetadataSet.ToString(), a.Id, a.AgencyId, a.Version);
                        ReferenceManager.ArTypedCopyInstanceUrn =
                            UrnManager.FullIdToUrn(SdmxArtefactType.MetadataSet.ToString(), a.FullIdent, atv, null);
                        FillClipboard(mItem, ReferenceManager.ArTypedCopyInstanceUrn);
                    }

                }
            }
        }

        private void FillClipboard(ToolStripMenuItem mItem, string urn)
        {
            string restBase = string.Empty;

            if (mItem == null || mItem.Text == ITEM_REF_SDMX)
            {
                Clipboard.SetText(urn);
            }
            else if (mItem.Text == ITEM_REF_CSV)
            {
                string csvRest = MakeRestEntrySelection(ArtefactTypeToRest.RestExportBase, UrnManager.UrnToArtefactRefTyped(urn));
                Clipboard.SetText(csvRest); 
            }
            else if (mItem.Text == ITEM_REF_REST)
            {
                restBase = MakeRestEntrySelection(ArtefactTypeToRest.RestSdmxBase, UrnManager.UrnToArtefactRefTyped(urn));
                Clipboard.SetText(restBase);
            }
            else if (mItem.Text == ITEM_REF_FILE)
            {
                Clipboard.SetText(UrnManager.UrnToArtefactRefTyped(urn).FullIdent);
            }
        }

        private string MakeRestEntrySelection(string restBase, ArtefactRefTyped art)
        {
            string syntax = restBase + '/' +

            ArtefactTypeToRest.RestType(art.Type)
            + '/' +
           art.AgencyId + '/' +
           art.Id + '/' +
           art.Version;

            return syntax;
        }

        #endregion

        #region Options

        public string RepositorySelect(IWin32Window owner)
        {
            string group = string.Empty;
            try
            {
                DlgTinyRegistryConfig aDlg = new DlgTinyRegistryConfig();
                aDlg.ShowDialog(owner);
                group = aDlg.GroupId;
                //Now update menu enabling
                if (tv != null)
                    treeView_AfterSelect(tv, new TreeViewEventArgs(tv.SelectedNode));

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            return group;
        }
        /// <summary> Redefine repository source </summary>
        /// <param name="sender"></param> <param name="e"></param>
        public void repositoryOptionToolStripMenuItem_Click(object sender, EventArgs e)
        {
            RepositorySelect(tv.Parent);
        }

        #region DEC 03.08.2011
        private void repositoryOptionImportToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                DlgImportRepository aDlg = new DlgImportRepository();
                aDlg.ShowDialog();

                //Now update menu enabling
                if (tv != null)
                    treeView_AfterSelect(tv, new TreeViewEventArgs(tv.SelectedNode));

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

        }
        #endregion
       
        #endregion

        #region References via Xml Base

        public void RefererViaXmlBase()
        {
            try
            {
                SmManager sm = ReferenceManager.GetSmContainerImage();
                if (_dlgReferrer == null)
                {
                    _dlgReferrer = new DlgReferrer();
                    _dlgReferrer.FormClosed += new FormClosedEventHandler(_dlgReferrer_FormClosed);
                }
                _dlgReferrer.Update(tv);
                _dlgReferrer.WindowState = FormWindowState.Normal;
                _dlgReferrer.Focus();
                _dlgReferrer.Show();

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        void _dlgReferrer_FormClosed(object sender, FormClosedEventArgs e)
        {
            _dlgReferrer = null;
        }

        #endregion

        #region Memory References

        public void MemoryRef()
        {
            try
            {
                if (_dlgMemoryRef == null)
                {
                    _dlgMemoryRef = new DlgMemoryRef();
                    _dlgMemoryRef.FormClosed += new FormClosedEventHandler(dlgMemoryRef_FormClosed);
                }
                _dlgMemoryRef.Update(tv);
                _dlgMemoryRef.WindowState = FormWindowState.Normal;
                _dlgMemoryRef.Focus();
                _dlgMemoryRef.Show();

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        void dlgMemoryRef_FormClosed(object sender, FormClosedEventArgs e)
        {
            _dlgMemoryRef = null;
        }

        #endregion

        #region Event CSV data association

        /// <summary>Event request for CSV Data association to MetaData</summary>
        /// <param name="sender"></param> <param name="e"></param>
        private void cSVToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                if (_dlgDataCsv == null)
                {
                    _dlgDataCsv = new DlgDataCsv(CsvConfig);
                    _dlgDataCsv.FormClosed += new FormClosedEventHandler(dlgDataCsv_FormClosed);
                }
                _dlgDataCsv.WindowState = FormWindowState.Normal;
                _dlgDataCsv.Focus();
                _dlgDataCsv.Show();
               
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

        }

        void dlgDataCsv_FormClosed(object sender, FormClosedEventArgs e)
        {
            _dlgDataCsv = null;
        }
        #endregion

        #region Event DSD Wizard

        void DSDWizardToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                if (_dlgDsdWizard == null)
                {
                    _dlgDsdWizard = new DlgDsdWizard();
                    _dlgDsdWizard.FormClosed += new FormClosedEventHandler(DlgDsdWizard_FormClosed);
                }
                _dlgDsdWizard.WindowState = FormWindowState.Normal;
                _dlgDsdWizard.Focus();
                _dlgDsdWizard.Show();
               
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        void DlgDsdWizard_FormClosed(object sender, FormClosedEventArgs e)
        {
            _dlgDsdWizard = null;
        }

        #endregion

        
         #region find in Annotations

        void FindInAnnotationsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                if (_dlgSearchAnnot == null)
                {
                    _dlgSearchAnnot = new DlgSearchAnnotations();
                    _dlgSearchAnnot.FormClosed += new FormClosedEventHandler(FindInAnnotationsToolStripMenuItem_FormClosed);
                }
                _dlgSearchAnnot.WindowState = FormWindowState.Normal;
                _dlgSearchAnnot.Focus();
                _dlgSearchAnnot.Show();
               
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        void FindInAnnotationsToolStripMenuItem_FormClosed(object sender, FormClosedEventArgs e)
        {
            _dlgSearchAnnot = null;
        }

        #endregion

        #region sort list selected in tree

        // Menu item for sort action
        public ToolStripButton ToolStripButtonSortList
        {
            get { return toolStripButtonSortList; }

            set
            {
                toolStripButtonSortList = value;
                if (toolStripButtonSortList != null)
                {
                    toolStripButtonSortList.Enabled = false;
                    toolStripButtonSortList.Click += toolStripButtonSortList_Click;
                }
            }
        }
        /// <summary>
        /// Sort list Event  (Can be hierarchical)
        /// </summary>
        /// <param name="sender"></param> <param name="e"></param>
        private void toolStripButtonSortList_Click(object sender, EventArgs e)
        {
            tv.BeginUpdate();
            TreeNode selectedNode = tv.SelectedNode;
            
            try
            {
                if (selectedNode.Tag is Artefact)
                {
                    if (selectedNode.Nodes.Count > 0)
                        selectedNode = selectedNode.Nodes[0];
                    else
                        return;
                }
               
                if (selectedNode != null && selectedNode.Tag is FlatHierarchicalList)
                {
                    FlatHierarchicalList fhl = selectedNode.Tag as FlatHierarchicalList;
                    fhl.Sort(Control.ModifierKeys == Keys.Control);
                    selectedNode.Nodes.Clear();
                    fhl.FillTree(selectedNode);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                tv.EndUpdate();
            }
        }


        #endregion
    }

}
